package com.whately.core.base.jwt.interceptor;

import com.whately.core.base.config.interceptor.NotNeedAccessApiUtil;
import com.whately.core.base.constant.ConstantProject;
import com.whately.core.base.constant.DebugSwitcher;
import com.whately.core.base.constant.LoginUser;
import com.whately.core.base.exception.GatewayException;
import com.whately.core.base.exception.ServiceError;
import com.whately.core.base.exception.ServiceException;
import com.whately.core.base.jwt.util.JWTUtil;
import com.whately.core.base.utils.HttpRequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * PreRequestAspect
 */
@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
    //private static final ThreadLocal<LoginUser> currentThreadLoginUser = new ThreadLocal();

    private static final ThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("ThreadLocal StartTime");



    @Autowired
    private NotNeedAccessApiUtil notNeedAccessApiUtil;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {

        // 1、开始时间
        long beginTime = System.currentTimeMillis();
        // 线程绑定变量（该数据只有当前请求的线程可见）
        startTimeThreadLocal.set(beginTime);

        String paramsMethodName = httpServletRequest.getParameter("method");

        if (StringUtils.isBlank(paramsMethodName)) {
            log.error("bad request method params is null {}", paramsMethodName);
            throw new GatewayException(ServiceError.REQUEST_PARAMETER_ERROR.getCode(), "请求参数异常：缺少必要参数");
        }

        //内部api和内部controller
        if (notNeedAccessApiUtil.isInner(handler)) {
            log.error("inner api {}" ,paramsMethodName);
            throw new GatewayException(ServiceError.REQUEST_PARAMETER_ERROR.getCode(),"请求参数异常：inner url");
        }

        //不需要校验SESSION的场景
        if (notNeedAccessApiUtil.isIgnore(handler)) {
            return true;
        }

        //开启debug=xyz模式,则通过，只有测试环境才有可能开启
        if (DebugSwitcher.isDebugOpen(httpServletRequest)) {
            return true;
        }

        String token = httpServletRequest.getHeader(ConstantProject.response_header_token_name);// 从 http 请求头中取出 token

        //"undefined".equals(token) 或者 null
        if (token == null|| StringUtils.isBlank(token)||token.length()<=10) {
            throw new ServiceException(ServiceError.SESSION_TIME_OUT);
        }

        LoginUser jwtUser = JWTUtil.fetchJwtUserFromToken(token);
        if(jwtUser==null){
            throw new ServiceException(ServiceError.SESSION_TIME_OUT);
        }

        //登录即放行的接口
        if(notNeedAccessApiUtil.isPermitAfterLogin(jwtUser,handler)){
            return true;
        }

        validSessionAfter(httpServletRequest,jwtUser,paramsMethodName);
        //currentThreadLoginUser.set(jwtUser);
        return true;
    }

    /**
     * 继承后的校验
     */
    public void validSessionAfter(HttpServletRequest httpServletRequest,LoginUser jwtUser,String paramsMethodName) throws Exception{

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        //currentThreadLoginUser.remove();

        // 得到线程绑定的局部变量（开始时间）
        Long beginTime = startTimeThreadLocal.get();
        if (beginTime == null) {
            return;
        }

        // 2、结束时间
        long endTime = System.currentTimeMillis();

        //超过2秒，记录
        long timeout = endTime - beginTime;
        if (timeout > 2 * 1000) {
            log.warn("rcr method call exceed 2 second here, call uri {},params {}", httpServletRequest.getRequestURI(), HttpRequestUtil.getRequestInfo(httpServletRequest));
        }
    }

   /* public static LoginUser getCurrentLoginUser() {
        return (LoginUser)currentThreadLoginUser.get();
    }*/
}
